/*
 * 版权所有 (C) 2015 知启蒙(ZHIQIM) 保留所有权利。[遇见知启蒙，邂逅框架梦]
 * 
 * https://zhiqim.org/project/zhiqim_framework/zhiqim_httpd.htm
 *
 * Zhiqim Httpd is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package org.zhiqim.httpd.sessioner;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.zhiqim.httpd.HttpSession;
import org.zhiqim.httpd.HttpSessionUser;
import org.zhiqim.httpd.model.HttpDomainPortPath;
import org.zhiqim.kernel.httpclient.HttpRMI;
import org.zhiqim.kernel.json.Jsons;
import org.zhiqim.kernel.paging.PageBuilder;
import org.zhiqim.kernel.paging.PageResult;
import org.zhiqim.kernel.util.Arrays;
import org.zhiqim.kernel.util.Asserts;
import org.zhiqim.kernel.util.Classes;
import org.zhiqim.kernel.util.Ids;
import org.zhiqim.kernel.util.Ints;
import org.zhiqim.kernel.util.Lists;
import org.zhiqim.kernel.util.Validates;

/**
 * RMI会话管理器，通过RMI访问Sessioner工程对会话进行管理
 *
 * @version v1.0.0 @author zouzhigang 2014-3-21 新建与整理
 */
public class RmiSessionManager extends AbsSessionManager
{
    private static final String SESSIONER = "sessioner";
    
    //四个接口定义参数
    private String url;
    private String key;
    private String secret;
    
    /**************************************************************************************/
    //开启和关闭
    /**************************************************************************************/
    
    @Override /** 开启会话管理器 */
    public void open()
    {
    }
    
    @Override /** 关闭会话管理器 */
    public void close()
    {
    }
    
    /**************************************************************************************/
    //设置参数部分
    /**************************************************************************************/
    
    @Override /** 设置会话编号名称 */
    public void setSessionIdName(String sessionIdName)
    {
    }
    
    @Override /** 设置会话超时时长 */
    public void setSessionTimeout(int sessionTimeout)
    {
    }
    
    @Override /** 设置会话管理器参数，Hash模式无需参数 */
    public void setSessionParameter(String sessionParameter)
    {
        String[] params = Arrays.toStringArray(sessionParameter);
        this.url = params[0];
        this.key = params[1];
        this.secret = params[2];
    }
    
    /**************************************************************************************/
    //获取参数部分
    /**************************************************************************************/
    
    @Override /** 获取会话编号名称 */
    public String getSessionIdName()
    {
        HttpRMI conn = createRMI();
        conn.setMethodName("getSessionIdName");
        conn.execute();
        
        if (!conn.isResponseSuccess())
        {
            throw Asserts.exception(conn.getResponseText());
        }
        
        return conn.getResponseText();
    }
    
    @Override /** 获取超时时长 */
    public int getSessionTimeout()
    {
        HttpRMI conn = createRMI();
        conn.setMethodName("getSessionTimeout");
        conn.execute();
        
        if (!conn.isResponseSuccess())
        {
            throw Asserts.exception(conn.getResponseText());
        }
        
        return Ints.toInt(conn.getResponseText());
    }
    
    public String getUrl()
    {
        return url;
    }
    
    /**************************************************************************************/
    //新建 & 保存 & 获取 & 失效 & 更新会话
    /**************************************************************************************/
    
    @Override /** 新建会话 */
    public HttpSession newSession(HttpDomainPortPath domainPortPath, String sessionIp, String userAgent)
    {
        String mark = (sessionIdMark != null)?sessionIdMark:domainPortPath.buildSessionIdMark();
        return new RmiSession(Ids.uuid()+mark, sessionIp, userAgent, this);
    }
    
    @Override /** 保存会话 */
    public void setSession(HttpSession session)
    {
        HttpRMI conn = createRMI();
        conn.setMethodName("setSession");
        conn.addParam(session.toString());
        conn.execute();
        
        if (!conn.isResponseSuccess())
        {
            throw Asserts.exception(conn.getResponseText());
        }
    }
    
    @Override /** 通过会话编号获取会话对象 */
    public HttpSession getSession(String sessionId)
    {
        HttpRMI conn = createRMI();
        conn.setMethodName("getSession");
        conn.addParam(sessionId);
        conn.execute();
        
        if (!conn.isResponseSuccess())
        {//服务端响应失败
            throw Asserts.exception(conn.getResponseText());
        }
        
        String responseText = conn.getResponseText();
        if (Validates.isEmptyBlank(responseText))
        {//服务端会话不存在
            throw Asserts.exception("获取会话失败，请重试");
        }
        
        RmiSession session = new RmiSession();
        session.setSessionManager(this);
        session.parse(responseText);
        return session;
    }
    
    @Override /** 判断会话是否存在 */
    public boolean hasSession(String sessionId)
    {
        HttpRMI conn = createRMI();
        conn.setMethodName("hasSession");
        conn.addParam(sessionId);
        conn.execute();
        
        if (!conn.isResponseSuccess())
        {//服务端响应失败
            throw Asserts.exception(conn.getResponseText());
        }
        
        return _TRUE_.equals(conn.getResponseText());
    }
    
    @Override /** 删除一个会话，指定会话编号 */
    public void invalidateSession(String sessionId)
    {
        HttpRMI conn = createRMI();
        conn.setMethodName("invalidateSession");
        conn.addParam(sessionId);
        conn.execute();
        
        if (!conn.isResponseSuccess())
        {//服务端响应失败
            throw Asserts.exception(conn.getResponseText());
        }
    }
    
    @Override /** 更新会话最后访问时间 */
    public void updateLastAccessed(String sessionId)
    {
        HttpRMI conn = createRMI();
        conn.setMethodName("updateLastAccessed");
        conn.addParam(sessionId);
        conn.execute();
        
        if (!conn.isResponseSuccess())
        {//服务端响应失败
            throw Asserts.exception(conn.getResponseText());
        }
    }
    
    @Override /** 更新会话信息 */
    public void updateInfo(String sessionId, String sessionIp, String userAgent)
    {
        HttpRMI conn = createRMI();
        conn.setMethodName("updateInfo");
        conn.addParam(sessionId);
        conn.addParam(sessionIp);
        conn.addParam(userAgent);
        conn.execute();
        
        if (!conn.isResponseSuccess())
        {//服务端响应失败
            throw Asserts.exception(conn.getResponseText());
        }
    }
    
    @Override /** 更新会话并返回会话 */
    public HttpSession getSessionByUpdate(String sessionId, String sessionIp, String userAgent)
    {
        HttpRMI conn = createRMI();
        conn.setMethodName("getSessionByUpdate");
        conn.addParam(sessionId);
        conn.addParam(sessionIp);
        conn.addParam(userAgent);
        conn.execute();
        
        if (!conn.isResponseSuccess())
        {//服务端响应失败
            throw Asserts.exception(conn.getResponseText());
        }
        
        String responseText = conn.getResponseText();
        if (Validates.isEmptyBlank(responseText))
        {//服务端会话不存在
            throw Asserts.exception("获取会话失败，请重试");
        }
        
        RmiSession session = new RmiSession();
        session.setSessionManager(this);
        session.parse(responseText);
        return session;
    }
    
    /**************************************************************************************/
    //会话查询和统计
    /**************************************************************************************/
    
    @Override /** 查会话数 */
    public int size()
    {
        HttpRMI conn = createRMI();
        conn.setMethodName("size");
        conn.execute();
        
        if (!conn.isResponseSuccess())
        {
            throw Asserts.exception(conn.getResponseText());
        }

        return Ints.toInt(conn.getResponseText());
    }
    
    @Override /** 获取会话列表 */
    public List<HttpSession> getSessionList()
    {
        HttpRMI conn = createRMI();
        conn.setMethodName("getSessionList");
        conn.execute();
        
        if (!conn.isResponseSuccess())
        {
            throw Asserts.exception(conn.getResponseText());
        }

        List<RmiSession> list = Jsons.toList(conn.getResponseText(), RmiSession.class);
        ArrayList<HttpSession> nList = new ArrayList<>(list.size());
        for (HttpSession s : list)
        {
            nList.add(s);
        }
        
        return Collections.unmodifiableList(Lists.trim(nList));
    }
    
    @Override /** 获取会话分页信息 */
    public PageResult<HttpSession> getSessionPage(int pageNo, int pageSize)
    {
        int size = size();
        if (size == 0)
            return PageBuilder.newResult(pageNo, pageSize);
        
        HttpRMI conn = createRMI();
        conn.setMethodName("getSessionList");
        conn.addParam(pageNo);
        conn.addParam(pageSize);
        conn.execute();
        
        if (!conn.isResponseSuccess())
        {
            throw Asserts.exception(conn.getResponseText());
        }
        
        List<RmiSession> list = Jsons.toList(conn.getResponseText(), RmiSession.class);
        ArrayList<HttpSession> nList = new ArrayList<>(list.size());
        for (HttpSession s : list)
        {
            nList.add(s);
        }
        
        return PageBuilder.newResult(size, pageNo, pageSize, nList);
    }
    
    /**************************************************************************************/
    //会话用户查询和统计
    /**************************************************************************************/
    
    @Override /** 查用户数，有登录状态 */
    public int sizeUser()
    {
        HttpRMI conn = createRMI();
        conn.setMethodName("sizeUser");
        conn.execute();
        
        if (!conn.isResponseSuccess())
        {
            throw Asserts.exception(conn.getResponseText());
        }

        return Ints.toInt(conn.getResponseText());
    }
    
    @Override /** 是否有会话名称对应的会话 */
    public boolean hasSessionName(String sessionName)
    {
        Asserts.notNull(sessionName, "sessionName");
        
        HttpRMI conn = createRMI();
        conn.setMethodName("hasSessionName");
        conn.addParam(sessionName);
        conn.execute();
        
        if (!conn.isResponseSuccess())
        {
            throw Asserts.exception(conn.getResponseText());
        }
        
        return _TRUE_.equals(conn.getResponseText());
    }
    
    @Override /** 获取会话登录用户列表，指定会话用户类名（如前后端共用session管理器的情况） */
    public List<HttpSessionUser> getSessionUserList()
    {
        HttpRMI conn = createRMI();
        conn.setMethodName("getSessionUserList");
        conn.execute();
        
        if (!conn.isResponseSuccess())
        {
            throw Asserts.exception(conn.getResponseText());
        }

        List<HttpSessionUser> list = new ArrayList<>();
        List<String> strList = Jsons.toList(conn.getResponseText(), String.class);
        for (String str : strList)
        {
            String className = Jsons.getString(str, "className");
            Class<?> clazz = Classes.forName(className);
            if (clazz == null)
                continue;
            
            HttpSessionUser sessionUser = (HttpSessionUser)Jsons.toObject(str, clazz);
            list.add(sessionUser);
        }
        
        return Lists.trim(list);
    }
    
    @Override /** 获取会话登录用户分页信息，指定会话用户类名（如前后端共用session管理器的情况） */
    public PageResult<HttpSessionUser> getSessionUserPage(int pageNo, int pageSize)
    {
        int size = sizeUser();
        if (size == 0)
            return PageBuilder.newResult(pageNo, pageSize);
        
        HttpRMI conn = createRMI();
        conn.setMethodName("getSessionUserList");
        conn.addParam(pageNo);
        conn.addParam(pageSize);
        conn.execute();
        
        if (!conn.isResponseSuccess())
        {
            throw Asserts.exception(conn.getResponseText());
        }

        List<HttpSessionUser> list = new ArrayList<>();
        List<String> strList = Jsons.toList(conn.getResponseText(), String.class);
        for (String str : strList)
        {
            String className = Jsons.getString(str, "className");
            Class<?> clazz = Classes.forName(className);
            if (clazz == null)
                continue;
            
            HttpSessionUser sessionUser = (HttpSessionUser)Jsons.toObject(str, clazz);
            list.add(sessionUser);
        }
        
        return PageBuilder.newResult(size, pageNo, pageSize, list);
    }
    
    /**************************************************************************************/
    //会话RMI连接
    /**************************************************************************************/
    
    /** 创建RMI连接 */
    private HttpRMI createRMI()
    {
        HttpRMI conn = new HttpRMI(url);
        conn.setConnectTimeout(10);
        conn.setReadTimeout(30);
        conn.setKeySecret(key, secret);
        conn.setServiceId(SESSIONER);
        
        return conn;
    }
}
